
package com.scalar.chiptrack.jobs;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import com.scalar.chiptrack.jobs.dao.JobDAO;
import com.scalar.chiptrack.utils.ConfigManager;
import com.scalar.chiptrack.utils.Mailer;


public class JobRunner {

    public static final int JOB_RUNNER_STOPPED = 0;
    public static final int JOB_RUNNER_STARTED = 1;
    private static final int HASH_MAP_INITIAL_CAPACITY = 32;

    private static JobRunner s_jobRunner = null;
    //private Timer m_timer = null;
    private CleanupJob m_jobCleanup = null;
    private JobPoller m_jobPoller = null;
    private Map m_scheduledJobs = null;
    private int m_status = -1;
    private Date m_jobRunnerStartTime = null;


    private JobRunner() {
        m_scheduledJobs = Collections.synchronizedMap (new HashMap (HASH_MAP_INITIAL_CAPACITY));
        m_status = JOB_RUNNER_STOPPED;
    }

    public static JobRunner getInstance() {
         synchronized (JobRunner.class){
            if (s_jobRunner == null) {

                // added
                // method to add to changes the job in the running state to abort..
                // what about the time of end and time taken fields
                try{

                     JobDAO.abortAllRunningJobs();

                }catch(Exception e){ }

                s_jobRunner = new JobRunner();
            }
         }
        return s_jobRunner;
    }

    public void execute (Job job) {

        try {
           // new JobRunnerThread (job).start(); this thread class is not required.
            jobrun(job);
        }
        catch (Throwable t) {
            System.out.println ("Exception while running the job - " + job.getName() + ": " + t);
            t.printStackTrace();
        }
    }
     // added
     // insted of JobRunnerThread this method is implemented
     // just copied the rin method of the JobRunnerThread.

     public void jobrun(Job job) {

            if (job == null) {
                return;
            }

            JobHandler handler = null;
            try {
                handler = job.getHandlerObject();
                handler.setName(job.getName());
            }
            catch (Exception e) {
                System.out.println ("\nJob Scheduler: Could not load JobHandler object for Job \"" + job.getName());
                System.out.println ("Exception Message: " + e);
                e.printStackTrace();
            }

            JobHandler runningJob = (JobHandler) m_scheduledJobs.get (job.getId()+"");
            if (((runningJob != null) && (runningJob.getStatus().equalsIgnoreCase(Job.STATUS_DONE) == false)) && (runningJob.canOverlap() == false)) {
                System.out.println ("\nJob Scheduler: Skipping Job, " + job.getName() + " -- Previously scheduled job is still running");
                return;
            }
            // run now
            //if (m_timer != null) { // removed

                // add job to list
                m_scheduledJobs.put (job.getId()+"", handler);

                if (job.getStartTime() == null) {
                    //m_timer.schedule (handler, 0); // schedule right now
                    handler.jobAddToTimer(0);
                }
                else {
                    //m_timer.schedule (handler, job.getStartTime());
                    handler.jobAddToTimer(job.getStartTime());
                }
                System.out.println("job id " + job.getId() +"is running added to timer to run");
            //}  // removed
        }

    /*public class JobRunnerThread extends Thread {

        private Job job = null;

        public JobRunnerThread (Job jobToRun) {
            job = jobToRun;
        }

        public void run() {

            if (job == null) {
                return;
            }

            JobHandler handler = null;
            try {
                handler = job.getHandlerObject();
                handler.setName(job.getName());
            }
            catch (Exception e) {
                System.out.println ("\nJob Scheduler: Could not load JobHandler object for Job \"" + job.getName());
                System.out.println ("Exception Message: " + e);
                e.printStackTrace();
            }

            JobHandler runningJob = (JobHandler) m_scheduledJobs.get (job.getId()+"");
            if (((runningJob != null) && (runningJob.getStatus().equalsIgnoreCase(Job.STATUS_DONE) == false)) && (runningJob.canOverlap() == false)) {
                System.out.println ("\nJob Scheduler: Skipping Job, " + job.getName() + " -- Previously scheduled job is still running");
                return;
            }


            // run now
            if (m_timer != null) {

                // add job to list
                m_scheduledJobs.put (job.getId()+"", handler);

                if (job.getStartTime() == null) {
                    m_timer.schedule (handler, 0); // schedule right now
                }
                else {
                    m_timer.schedule (handler, job.getStartTime());
                }
            }
        }
    } */


    public class JobPoller extends TimerTask {
                                //implements Runnable {  implements is not required

        private boolean jobPollerStarted = false;
        private Timer timer = null;

        public JobPoller() {
        }

        public void start() {
             // new Thread (this).start(); new thread start is not required.
            if (jobPollerStarted == false) {
                    jobPollerStarted = true;
                    timer = new Timer();
                    timer.scheduleAtFixedRate (this, 0, ConfigManager.getJobPollingPeriod());
            }
        }

        public void stop() {
            if ((timer != null) && (jobPollerStarted == true)) {

                try {
                    jobPollerStarted = false;
                    timer.cancel();
                }
                catch (Exception e) {
                    System.out.println ("Exception while stopping Job Poller: " + e);
                    e.printStackTrace();
                    jobPollerStarted = false;
                }
            }
        }

        public boolean isStarted() {
            return jobPollerStarted;
        }


        // check database for ready-to-run jobs
        public void run() {

            try {
               /* if (jobPollerStarted == false) {
                    jobPollerStarted = true;

                    timer = new Timer();
                    timer.scheduleAtFixedRate (this, 0, ConfigManager.getJobPollingPeriod());

                    return;
                } */

                if (s_jobRunner == null) {
                    s_jobRunner = getInstance();
                }

                try {
                    //System.out.println ("job poller running");

                    ArrayList jobList = JobDAO.loadAllJobs();


                    if ((jobList == null) || (jobList.size() == 0)) {
                        //System.out.println ("No jobs to run");
                        return;
                    }

                    //System.out.println ("Job size = " + jobList.size());
                    //for (int i=0; i<jobList.size(); i++) {
                        //System.out.println ("Job[" + i + "] = " + jobList.get(i));
                    //}

                    Iterator readyToRunJobs = getReadyToRunJobs (jobList);

                    while (readyToRunJobs.hasNext()) {
                        s_jobRunner.execute ((Job)readyToRunJobs.next());
                    }
                }
                catch (Exception e) {
                    System.err.println ("JobPoller: Exception while trying to run jobs from database");
                    System.err.println ("Exception Message: " + e.getMessage());
                    e.printStackTrace();
                }
            }
            catch (Exception e) {
                System.out.println ("Exception while running Job Poller: " + e);
                e.printStackTrace();
                jobPollerStarted = false;
            }

        }


        private Iterator getReadyToRunJobs (ArrayList jobList) {

            long pollingPeriod = ConfigManager.getJobPollingPeriod();
            int size = jobList.size();

            Date startTime = null;
            long frequency = 0;
            long nextStartTime = 0;
            Job job = null;
            HashMap readyToRunJobsMap = new HashMap();

            for (int i=0; i<size; i++) {

                job = (Job) jobList.get(i);

                if (readyToRunJobsMap.get (job.getJobName()) != null) {
                    continue;
                }
                /*
                startTime = job.getStartTime();
                frequency = job.getFrequency(); // in minutes

                if (startTime == null) {    // Run right now

                    JobHandler runningJob = (JobHandler) m_scheduledJobs.get (job.getId()+"");
                    if (((runningJob != null) && (runningJob.getStatus().equalsIgnoreCase(Job.STATUS_DONE) == false)) && (runningJob.canOverlap() == false)) {
                        System.out.println ("\nJob Scheduler: Skipping Job, " + job.getName() + " -- Previously scheduled job is still running");
                    }
                    else {
                        System.out.println ("\nJob Poller: " + job.getName() + "[ID = " + job.getId() + "] has to be started right away, added to list");
                        readyToRunJobsMap.put (job.getHandler(), job);
                    }
                }

                else if (frequency <= 0) {
                    continue;   // Not a periodic-job
                }

                else {

                    nextStartTime = startTime.getTime();
                    long rightNow = System.currentTimeMillis();

                    while (nextStartTime < rightNow) { // re-calculate job start-time, only if the start time is less than current millis
                        nextStartTime += (frequency*60*1000);
                    }

                    System.out.println ("\nJob Poller: [Job ID = " + job.getId() + "] nextStartTime - right now = " + (nextStartTime - rightNow));

                    if (((nextStartTime - rightNow) > 0) && ((nextStartTime - rightNow) <= pollingPeriod)){

                        JobHandler runningJob = (JobHandler) m_scheduledJobs.get (job.getId()+"");
                        if (((runningJob != null) && (runningJob.getStatus().equalsIgnoreCase(Job.STATUS_DONE) == false)) && (runningJob.canOverlap() == false)) {
                            //System.out.println ("\nJob Scheduler: Skipping Job, " + job.getName() + " -- Previously scheduled job is still running");
                        }
                        else {
                            System.out.println ("\nJob Poller: " + job.getName() + " has to start at " + new Date (nextStartTime) + " added to list");
                            readyToRunJobsMap.put (job.getHandler(), job);
                        }
                    }
                } */
                //Commented above code and written below code. Phani 07/07/2004.
                //checking weather Job's Start Date is null. If it is null, it won't considered for scheduling.
                if ( job.getStartDate() != null )
                {
                    boolean processJob = false;

                    Calendar startDate = Calendar.getInstance();
                    startDate.setTime( com.scalar.chiptrack.utils.StringUtils.format(job.getStartDate().substring(0, 10), "MM/dd/yyyy" ) );
                    startDate.set( Calendar.AM_PM, Calendar.AM );
                    startDate.set( Calendar.HOUR, 0);
                    startDate.set( Calendar.MINUTE, 0);
                    startDate.set( Calendar.SECOND, 0);
                    startDate.set( Calendar.MILLISECOND, 0);

                    Calendar endDate = null;
                    if ( job.getEndDate() != null )
                    {
                        endDate = Calendar.getInstance();
                        endDate.setTime( com.scalar.chiptrack.utils.StringUtils.format(job.getEndDate().substring(0, 10), "MM/dd/yyyy" ) );
                        endDate.set( Calendar.AM_PM, Calendar.PM );
                        endDate.set( Calendar.HOUR, 11);
                        endDate.set( Calendar.MINUTE, 59);
                        endDate.set( Calendar.SECOND, 59);
                        endDate.set( Calendar.MILLISECOND, 999);
                    }

                    long rightNow = System.currentTimeMillis();

                    //If current date and time is less than Job's Start Date, Job won't be considered for scheduling.
                    if ( rightNow >= startDate.getTime().getTime() )
                    {
                        //if current date and time later than End Date and repeated task not checked, Job won't be considered for scheduling.
                        if ( endDate != null && (rightNow > endDate.getTime().getTime() ) )
                        {
                            //These two Frequencies sum greater than zero means, Repeat Task is Checked.
                             if ( job.getFrequencyInHours() + job.getFrequencyInMinutes() <= 0  )
                             {
                                continue;
                             }
                        }

                        Calendar curCal = Calendar.getInstance ();
                        curCal.set( Calendar.AM_PM, Calendar.AM );
                        curCal.set( Calendar.HOUR, 0);
                        curCal.set( Calendar.MINUTE, 0);
                        curCal.set( Calendar.SECOND, 0);
                        curCal.set( Calendar.MILLISECOND, 0);

                        if ( job.getOccurs().equalsIgnoreCase("Daily"))        //if Job's occurs type is "Daily"
                        {
                            int scheduleDaysInt = 1;
                            try   {
                                scheduleDaysInt = Integer.parseInt( job.getEveryDaily() );
                            }
                            catch (NumberFormatException nfe)    {
                            }

                            while ( startDate.getTime().getTime() < curCal.getTime().getTime() )
                            {
                                startDate.add(Calendar.DATE, scheduleDaysInt);
                            }

                            if ( startDate.getTime().getTime() == curCal.getTime().getTime() )
                            {
                                processJob = true;
                            }
                        }//Daily
                        else if ( job.getOccurs().equalsIgnoreCase("Weekly"))  //if Job's occurs type is "Weekly"
                        {
                            //checking weather current day is in the selected list.
                            int dayOfWeek = curCal.get(Calendar.DAY_OF_WEEK );
                            String dayOfWeekStr = "";

                            switch ( dayOfWeek )
                            {
                                case 1:
                                    dayOfWeekStr = "Sun";
                                    break;
                                case 2:
                                    dayOfWeekStr = "Mon";
                                    break;
                                case 3:
                                    dayOfWeekStr = "Tue";
                                    break;
                                case 4:
                                    dayOfWeekStr = "Wed";
                                    break;
                                case 5:
                                    dayOfWeekStr = "Thu";
                                    break;
                                case 6:
                                    dayOfWeekStr = "Fri";
                                    break;
                                case 7:
                                    dayOfWeekStr = "Sat";
                                    break;
                            }

                            String selectedWeekDays[] = job.getSelectedWeekDays();

                            //checking for which day, the job has to run. if current date's week day doesn't exists in the
                            //selectedWeekDays of the job, this wouldn't be considered for scheduling.
                            for(int idx = 0; idx < selectedWeekDays.length; idx++ )
                            {
                                if ( selectedWeekDays[idx].equalsIgnoreCase(dayOfWeekStr) )
                                {
                                    processJob = true;
                                    break;
                                }
                            }

                            //processJob is true, then checking for "Every".
                            if ( processJob )
                            {
                                int weeksOn = 1;
                                try   {
                                    weeksOn = Integer.parseInt( job.getEveryWeekly() );
                                }
                                catch (NumberFormatException nfe)   {
                                }

                                //Moving forward the startDate to a date, whose day of the week is same as
                                //the current date's day of the week.
                                while (  startDate.get( Calendar.DAY_OF_WEEK ) != curCal.get( Calendar.DAY_OF_WEEK ) )
                                {
                                    //startDate.set( Calendar.DATE, 1);
                                    //startDate.roll(Calendar.DATE, true);
                                    startDate.setTimeInMillis( startDate.getTimeInMillis() + 24 * 60 * 60 * 1000 );
                                }

                                //if startDate is equal to current date (or) the date that come when we add multiples of
                                //weekOn *7 days to startDate is equalto current date, then we can schedule this job.
                                while ( startDate.getTime().getTime() < curCal.getTime().getTime() )
                                {
                                    //startDate.roll(Calendar.DATE, weeksOn * 7);
                                    startDate.setTimeInMillis( startDate.getTimeInMillis() + weeksOn * 7 * 24 * 60 * 60 * 1000 );
                                }

                                if ( curCal.getTime().getTime() == startDate.getTime().getTime() )
                                {
                                    processJob = true;
                                }
                                else
                                {
                                    processJob = false;
                                }
                            }//processJob
                        }//weekly
                        else if ( job.getOccurs().equalsIgnoreCase("Monthly")) //if Job's occurs type is "Monthly"
                        {
                             int scheduleDay = 0;
                             int months = 1;
                             try {
                                 scheduleDay = Integer.parseInt( job.getEveryDay() );
                                 months = Integer.parseInt( job.getEveryMonthly() );
                             } catch(NumberFormatException nfe) {}

                             //checking weather current dates's day matches with schedule day.
                             if ( curCal.get( Calendar.DAY_OF_MONTH) == scheduleDay )
                             {
                                 Calendar tempCal = Calendar.getInstance();
                                 tempCal.setTime( curCal.getTime() );
                                 tempCal.set( Calendar.DAY_OF_MONTH, 1);

                                 startDate.set( Calendar.DAY_OF_MONTH, 1);

                                 while ( startDate.getTime().getTime() < tempCal.getTime().getTime() )
                                 {
                                     startDate.add( Calendar.MONTH, months);
                                 }

                                 if ( startDate.getTime().getTime() == tempCal.getTime().getTime() )
                                 {
                                     processJob = true;
                                 }
                             }
                        }

                        if ( processJob )
                        {
                            curCal.set( Calendar.AM_PM, job.getAmPm() );
                            curCal.set( Calendar.HOUR, Integer.parseInt ( job.getScheduleTime()) );
                            //curCal.set( Calendar.MINUTE, 0);
                            curCal.set( Calendar.MINUTE, Integer.parseInt( job.getScheduleMinute() ));
                            curCal.set( Calendar.SECOND, 0);

                            frequency = job.getFrequencyInHours();

                            //When the Job is Scheduled at 12.00A.M,,,....Assigning next day's 12.00A.M to the nextStartTime.
                            if ( curCal.get( Calendar.HOUR ) == 0 && curCal.get( Calendar.MINUTE ) == 0 && curCal.get( Calendar.AM_PM ) == Calendar.AM )
                            {
                                nextStartTime = curCal.getTime().getTime() + 24*60*60*1000;
                            }
                            else
                            {
                                nextStartTime = curCal.getTime().getTime();
                            }

                            while (nextStartTime < rightNow && frequency > 0)
                            {
                                nextStartTime += (frequency*60*1000);  // re-calculate job start-time, only if the start time is less than current millis
                            }

                            //System.out.println ("\nJob Poller: [Job ID = " + job.getId() + "] nextStartTime - right now = " + (nextStartTime - rightNow));
                            if (((nextStartTime - rightNow) >= 0) && ((nextStartTime - rightNow) <= pollingPeriod)){

                                JobHandler runningJob = (JobHandler) m_scheduledJobs.get (job.getId()+"");
                                if (((runningJob != null) && (runningJob.getStatus().equalsIgnoreCase(Job.STATUS_DONE) == false)) && (runningJob.canOverlap() == false)) {
                                    //System.out.println ("\nJob Scheduler: Skipping Job, " + job.getName() + " -- Previously scheduled job is still running");
                                }
                                else {
                                    System.out.println ("\nJob Poller: " + job.getName() + " has to start at " + new Date (nextStartTime) + " added to list");
                                    job.setStartTime( new Date( nextStartTime ));
                                    readyToRunJobsMap.put (job.getJobName(), job);
                                }
                            }
                        }//if ( processJob)

                    }//if rightNow
                }//job.getStartDate != null
            }
            return readyToRunJobsMap.values().iterator();
        }
    }


     public class CleanupJob extends TimerTask {
                            // implements Runnable { this is not required

        private boolean cleanupJobStarted = false;
        private Timer timer = null;

        public CleanupJob() {
        }


        public void start() {
            // new Thread (this).start();
            if (cleanupJobStarted == false) {
                    cleanupJobStarted = true;
                    timer = new Timer();
                    timer.scheduleAtFixedRate (this, 0, ConfigManager.getJobRunnerCleanupPeriod());
            }
        }

        public void stop() {
            if (cleanupJobStarted == true) {

                try {
                    cleanupJobStarted = false;
                    timer.cancel();
                }
                catch (Exception e) {
                    System.out.println ("Exception while stopping Job Cleanup Thread: " + e);
                    e.printStackTrace();
                    cleanupJobStarted = true;
                }
            }
        }

        public boolean isStarted() {
            return cleanupJobStarted;
        }

        // Removed all finished jobs from map
        public void run() {

            try {
                 // this block is placed in the start method.
                /*if (cleanupJobStarted == false) {
                    cleanupJobStarted = true;

                    timer = new Timer();
                    timer.scheduleAtFixedRate (this, 0, ConfigManager.getJobRunnerCleanupPeriod());
                }*/

                //System.out.println ("JobRunner CLEANUP - STARTED");

                Iterator iterator = m_scheduledJobs.values().iterator();
                JobHandler jobHandler = null;
                ArrayList removableJobs = new ArrayList();
                ArrayList timedOutAbortedJobs = new ArrayList();
                boolean periodicJob = false;
                String jobStatus = Job.STATUS_NEW;

                while (iterator.hasNext()) {
                    jobHandler = (JobHandler) iterator.next();
                    if ( jobHandler != null )
                    {
                        jobStatus = jobHandler.getStatus();
                        //System.out.println ("jobname = " + job.getName() + ", status = " + jobStatus);
                        if ((jobStatus.equalsIgnoreCase(Job.STATUS_DONE)) ||
                            (jobStatus.equalsIgnoreCase(Job.STATUS_ABORTED) ||
                            (jobStatus.equalsIgnoreCase(Job.STATUS_FAILED))    ))
                        {
                                removableJobs.add (jobHandler.getJob().getId()+"");
                        }
                        else if ( jobStatus.equalsIgnoreCase( Job.STATUS_RUNNING ) )//NEED TO CHECK FOR THE JOB ABORT TIME
                        {
                            long endTime = System.currentTimeMillis();
                            long totalElapsedTime = ( endTime - jobHandler.getStartTime() );
                            long abortTime = ConfigManager.getJobAbortTime();
                            if ( totalElapsedTime >= abortTime )
                            {
                                jobHandler.abort();
                                removableJobs.add ( jobHandler.getJob().getId()+"" );
                                timedOutAbortedJobs.add ( jobHandler );
                                System.out.println (jobHandler.getName() + " [ID = " + jobHandler.getJob().getId() + "] has been aborted due to running after abort time");
                            }
                        }
                    }
                }

                String jobId = null;
                for (int i=0; i<removableJobs.size(); i++)
                {
                    jobId = (String) removableJobs.get(i);
                    m_scheduledJobs.remove (jobId);
                    System.out.println ("\nJob Cleanup Thread: Removed Job [ID = " + jobId + "]");
                }

                long endTime = System.currentTimeMillis();
                for ( int i=0; i < timedOutAbortedJobs.size(); i++ ) //NEED TO SEND NOTIFICATION MAIL
                {
                    jobHandler = (JobHandler)timedOutAbortedJobs.get( i );
                    String from = ConfigManager.getScalarAdminEmail();
                    String to = jobHandler.getJob().getEmails();
                    String subject = "Job " + jobHandler.getName() + " TIMED OUT Aborted Notification";
                    String message = "Job " + jobHandler.getName() + " Aborted as Timed Out at " + new Date ( endTime );
                    if ( from != null && to != null && from.length() > 0 && to.length() > 0 )
                    {
                        try
                        {
                            Mailer.send ( from, to, null, null, subject, message, null, Mailer.CONTENT_TYPE_HTML, false );
                        }
                        catch ( Exception e )
                        {
                            System.out.println ("Exception while TIMED OUT Aborted Notification: " + e);
                        }
                    }
                }
                timedOutAbortedJobs = null;
                //System.out.println ("JobRunner CLEANUP - DONE");
            }
            catch (Exception e) {
                System.out.println ("Exception while running Job Cleanup Thread: " + e);
                e.printStackTrace();
                cleanupJobStarted = false;
            }
        }
    }


    public void start() {
        if (m_status != JOB_RUNNER_STARTED) {

            //m_timer = new Timer();

            m_jobPoller = new JobPoller();
            m_jobPoller.start();

            m_jobCleanup = new CleanupJob();
            m_jobCleanup.start();

            m_status = JOB_RUNNER_STARTED;

            m_jobRunnerStartTime = new Date (System.currentTimeMillis());
        }
    }


    public void stop() {

        if (m_status != JOB_RUNNER_STOPPED) {
           // m_timer.cancel();
           // m_timer = null;

            // Stop all jobs
            int size = m_scheduledJobs.size();
            Iterator keys = m_scheduledJobs.keySet().iterator();

            while (keys.hasNext()) {
                ((JobHandler) m_scheduledJobs.remove (keys.next())).abort();
            }

            if (m_jobPoller != null) {
                m_jobPoller.stop();
                m_jobPoller = null;
            }

            if (m_jobCleanup != null) {
                m_jobCleanup.stop();
                m_jobCleanup = null;
            }

            m_status = JOB_RUNNER_STOPPED;
        }
    }

    public void abort (int jobId) {
	JobHandler jobHandler = (JobHandler) m_scheduledJobs.get (jobId+"");
        if (jobHandler != null) {
            jobHandler.abort();
            m_scheduledJobs.remove (jobId+"");
	}
    }

    public int getStatus() {
        return m_status;
    }

    public Date getJobRunnerStartTime() {
        return m_jobRunnerStartTime;
    }

    public String getStatusAsString() {
        if (m_status == JOB_RUNNER_STARTED) {
            return "Running, since " + m_jobRunnerStartTime;
        }

        return "Stopped";
    }

    public String getJobPollerStatus() {
        if (m_jobPoller == null) {
            return "Stopped";
        }

        if (m_jobPoller.isStarted() == true) {
            return "Running, every " + ConfigManager.getJobPollingPeriod() + " secs";
        }

        return "Stopped";
    }

    public String getCleanupJobStatus() {

        if (m_jobCleanup == null) {
            return "Stopped";
        }

        if (m_jobCleanup.isStarted() == true) {
            return "Running, every " + ConfigManager.getJobRunnerCleanupPeriod() + " secs";
        }

        return "Stopped";
    }

    public Object[] getJobInfo() {
        return m_scheduledJobs.values().toArray();
    }

    public static void main (String[] args) {
        System.setProperty("cmd", "");
        System.setProperty("scalar.properties", "c:/chiptrack/config/scalar.properties");
        JobRunner jobRunner = JobRunner.getInstance();
        jobRunner.start();
    }

}